package top.fyukina.fymil.parsers;

import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.Text;
import top.fyukina.fymil.elements.Environment;
import java.math.BigDecimal;
import java.math.RoundingMode;
import static top.fyukina.fymil.parsers.NumberParser.NumCalc.*;

public class NumberParser implements Parser<BigDecimal> {
    @Override
    public BigDecimal parse(Element tag, Environment env) {
        BigDecimal sum = BigDecimal.ZERO;
        NumCalc op = PLUS;
        for (Node node : tag.content()) {
            if (node instanceof Text t) {
                Object r = env.reg().comParser.
                        parseTry(env.reg().strParser.realTrim(t.getText()), env);
                if (r instanceof BigDecimal bd) {
                    sum = nextCalcNumber(sum, bd, op, env);
                } else if (r instanceof Boolean bl) {
                    sum = nextCalcNumber(sum,
                            bl ? BigDecimal.ONE : BigDecimal.ZERO, op, env);
                }
            } else if (node instanceof Element el0) {
                switch (el0.getName()) {
                    case "pl" -> op = PLUS;
                    case "rd" -> op = REDUCE;
                    case "mp" -> op = MULTIPLY;
                    case "dv" -> op = DIVIDE;
                    default -> {
                        Object r = env.reg().expParser.parse(el0, env);
                        if (r instanceof BigDecimal bd) {
                            sum = nextCalcNumber(sum, bd, op, env);
                        }
                    }
                }
            }
        }
        return sum;
    }
    public BigDecimal nextCalcNumber(BigDecimal origin, BigDecimal next,
                                     NumCalc op, Environment env) {
        switch (op) {
            case PLUS -> {
                return origin.add(next);
            }
            case REDUCE -> {
                return origin.subtract(next);
            }
            case MULTIPLY -> {
                return origin.multiply(next);
            }
            case DIVIDE -> {
                return origin.divide(next,
                        (Integer) env.p("numPrecision"),
                        RoundingMode.HALF_UP);
            }
            default -> {
                return origin;
            }
        }
    }
    @Override
    public ParserType registerName() {
        return ParserType.NUM;
    }

    public enum NumCalc {
        PLUS, REDUCE, MULTIPLY, DIVIDE
    }
}